﻿using System;
using System.Collections;
using System.Data;
using System.Globalization;
using System.IO;
using System.Xml;

public class CExWordMLFiller
{
    private static string amlPrefix = "http://schemas.microsoft.com/aml/2001/core";
    private bool bOperationFailed;
    private CultureInfo ci;
    private string dateTimeFormat;
    private DataSet dsData;
    private ArrayList errorList = new ArrayList();
    private string languageName;
    private XmlNamespaceManager nsmgr = new XmlNamespaceManager(new NameTable());
    private int numberDecimalDigits;
    private string numberDecimalSeparator;
    private NumberFormatInfo numberFormat;
    private string numberGroupSeparator;
    private const string repeatAttribute = "WMLRepeat";
    private string templateContent;
    private static string wordmlPrefix = "http://schemas.microsoft.com/office/word/2003/wordml";
    private XmlDocument xmlDataset;
    private XmlDocument xmlTemplateDoc;
    private static string xsPrefix = "http://www.w3.org/2001/XMLSchema";

    public CExWordMLFiller(DataSet dsData, string templateContent)
    {
        this.dsData = dsData;
        this.xmlDataset = new XmlDocument();
        MemoryStream stream = new MemoryStream();
        dsData.WriteXml(stream, XmlWriteMode.WriteSchema);
        stream.Seek(0L, SeekOrigin.Begin);
        XmlReader reader = new XmlTextReader(stream);
        this.xmlDataset.Load(reader);
        this.templateContent = templateContent;
        this.LoadTemplate();
    }

    public static string GetDataStructure(DataSet ds)
    {
        string str = string.Empty;
        string str2 = string.Empty;
        foreach (DataTable table in ds.Tables)
        {
            for (int i = 0; i < table.Columns.Count; i++)
            {
                if (str == string.Empty)
                {
                    str = str + table.TableName + table.Columns[i].ColumnName;
                    str2 = str2 + " ";
                }
                else
                {
                    str = str + "\t" + table.TableName + table.Columns[i].ColumnName;
                    str2 = "\t ";
                }
            }
        }
        return (str + Environment.NewLine + str2);
    }

    private void LoadTemplate()
    {
        this.errorList = new ArrayList();
        this.bOperationFailed = false;
        try
        {
            this.xmlTemplateDoc = new XmlDocument();
            this.xmlTemplateDoc.LoadXml(this.templateContent);
            this.nsmgr.AddNamespace("w", wordmlPrefix);
            this.nsmgr.AddNamespace("aml", amlPrefix);
            XmlNode node = this.xmlTemplateDoc.SelectSingleNode("//w:docVar[@w:name='LanguageName']/@w:val", this.nsmgr);
            if (node != null)
            {
                this.languageName = node.Value;
                try
                {
                    this.ci = new CultureInfo(this.languageName, false);
                    this.numberFormat = this.ci.NumberFormat;
                }
                catch
                {
                    this.languageName = null;
                    this.numberFormat = null;
                }
            }
            else
            {
                this.languageName = null;
            }
            node = this.xmlTemplateDoc.SelectSingleNode("//w:docVar[@w:name='DateTimeFormat']/@w:val", this.nsmgr);
            if (node != null)
            {
                this.dateTimeFormat = node.Value;
            }
            else
            {
                this.dateTimeFormat = "dd/MM/yyyy";
            }
            node = this.xmlTemplateDoc.SelectSingleNode("//w:docVar[@w:name='NumberDecimalSeparator']/@w:val", this.nsmgr);
            if (node != null)
            {
                this.numberDecimalSeparator = node.Value;
                if (this.numberFormat == null)
                {
                    this.numberFormat = new NumberFormatInfo();
                }
                this.numberFormat.NumberDecimalSeparator = (this.numberDecimalSeparator.Trim() == string.Empty) ? "." : this.numberDecimalSeparator;
            }
            else
            {
                this.numberDecimalSeparator = ".";
            }
            node = this.xmlTemplateDoc.SelectSingleNode("//w:docVar[@w:name='NumberGroupSeparator']/@w:val", this.nsmgr);
            if (node != null)
            {
                this.numberGroupSeparator = node.Value;
                if (this.numberFormat == null)
                {
                    this.numberFormat = new NumberFormatInfo();
                }
                this.numberFormat.NumberGroupSeparator = (this.numberGroupSeparator.Trim() == string.Empty) ? "," : this.numberGroupSeparator;
            }
            else
            {
                this.numberGroupSeparator = ",";
            }
            node = this.xmlTemplateDoc.SelectSingleNode("//w:docVar[@w:name='NumberDecimalDigits']/@w:val", this.nsmgr);
            if (node != null)
            {
                try
                {
                    this.numberDecimalDigits = int.Parse(node.Value);
                }
                catch
                {
                    this.numberDecimalDigits = -1;
                }
                if (this.numberFormat == null)
                {
                    this.numberFormat = new NumberFormatInfo();
                }
                this.numberFormat.NumberDecimalDigits = (this.numberDecimalDigits == -1) ? 2 : this.numberDecimalDigits;
            }
            else
            {
                this.numberDecimalDigits = 0;
            }
        }
        catch (Exception innerException)
        {
            while (innerException != null)
            {
                this.errorList.Add(innerException.Message);
                innerException = innerException.InnerException;
            }
            this.bOperationFailed = true;
        }
    }

    private void RemoveMailMergeNode()
    {
        this.errorList = new ArrayList();
        this.bOperationFailed = false;
        XmlNode oldChild = this.xmlTemplateDoc.SelectSingleNode("//w:mailMerge", this.nsmgr);
        if (oldChild == null)
        {
            this.errorList.Add("Invalid mail merge node!");
            this.bOperationFailed = true;
        }
        else
        {
            XmlNode parentNode = oldChild.ParentNode;
            if (parentNode == null)
            {
                this.errorList.Add("Invalid mail merge parent node!");
                this.bOperationFailed = true;
            }
            else
            {
                parentNode.RemoveChild(oldChild);
            }
        }
    }

    private void RemoveUnfilledFields()
    {
        this.errorList = new ArrayList();
        this.bOperationFailed = false;
        this.nsmgr.AddNamespace("xs", xsPrefix);
        XmlNodeList list = this.xmlDataset.SelectNodes("//xs:element", this.nsmgr);
        if ((list != null) && (list.Count != 0))
        {
            foreach (XmlNode node in list)
            {
                string attribute = ((XmlElement)node).GetAttribute("name");
                this.ReplaceFieldData(this.xmlTemplateDoc.DocumentElement, attribute, string.Empty, Type.Missing.GetType());
            }
        }
    }

    private void ReplaceFieldData(XmlNode baseNode, string fieldName, string data, Type colType)
    {
        this.errorList = new ArrayList();
        this.bOperationFailed = false;
        XmlNodeList list = baseNode.SelectNodes("//w:fldSimple[@w:instr=' MERGEFIELD  " + fieldName + " ']", this.nsmgr);
        if ((list == null) || (list.Count == 0))
        {
            list = baseNode.SelectNodes("//w:p[w:r/w:instrText=' MERGEFIELD  " + fieldName + " ']", this.nsmgr);
        }
        foreach (XmlNode node3 in list)
        {
            XmlNode node = node3.SelectSingleNode("//w:t[.='\x00ab" + fieldName + "\x00bb']", this.nsmgr);
            if (node == null)
            {
                this.errorList.Add("The field data is selected from the fields definition data source or merge document is corrupted!");
                this.bOperationFailed = true;
                break;
            }
            if (colType == typeof(DateTime))
            {
                if (this.dateTimeFormat != null)
                {
                    node.InnerText = DateTime.Parse(data).ToString(this.dateTimeFormat);
                }
                else
                {
                    node.InnerText = data;
                }
            }
            else if (colType == typeof(int))
            {
                if (this.numberFormat != null)
                {
                    node.InnerText = int.Parse(data).ToString(this.numberFormat);
                }
                else
                {
                    node.InnerText = data;
                }
            }
            else if (((colType == typeof(decimal)) || (colType == typeof(float))) || (colType == typeof(double)))
            {
                try
                {
                    node.InnerText = (data == "0") ? "" : data;
                }
                catch (Exception)
                {
                    node.InnerText = data;
                }
            }
            else
            {
                node.InnerText = data;
            }
            XmlNodeList list2 = node3.SelectNodes("w:r[w:fldChar]", this.nsmgr);
            if ((list2 != null) && (list2.Count > 0))
            {
                for (int i = list2.Count - 1; i >= 0; i--)
                {
                    list2[i].ParentNode.RemoveChild(list2[i]);
                }
            }
            XmlNode oldChild = node3.SelectSingleNode("w:r[w:instrText]", this.nsmgr);
            if (oldChild != null)
            {
                oldChild.ParentNode.RemoveChild(oldChild);
            }
        }
    }

    public void Transform()
    {
        foreach (DataTable table in this.dsData.Tables)
        {
            this.TransformDataTable(table);
        }
        this.RemoveMailMergeNode();
        this.RemoveUnfilledFields();
    }

    public void Transform_row()
    {
        foreach (DataTable table in this.dsData.Tables)
        {
            this.TransformDataTable_row(table);
        }
        this.RemoveMailMergeNode();
        this.RemoveUnfilledFields();
    }

    private void TransformDataRow(DataRow dr, XmlNode baseNode)
    {
        DataTable table = dr.Table;
        string tableName = table.TableName;
        XmlNode parentNode = baseNode.ParentNode;
        if (parentNode != null)
        {
            XmlNode node = baseNode.CloneNode(true);
            for (int i = 0; i < dr.ItemArray.Length; i++)
            {
                string fieldName = table.TableName + table.Columns[i].ColumnName;
                this.ReplaceFieldData(node, fieldName, dr[i].ToString(), table.Columns[i].DataType);
            }
            parentNode.InsertBefore(node, baseNode);
            parentNode.RemoveChild(baseNode);
        }
    }

    private void TransformDataRow(DataRow dr, XmlNode tableNode, XmlNode templateRowNode)
    {
        DataTable table = dr.Table;
        string tableName = table.TableName;
        XmlNode baseNode = templateRowNode.CloneNode(true);
        for (int i = 0; i < dr.ItemArray.Length; i++)
        {
            string fieldName = table.TableName + table.Columns[i].ColumnName;
            this.ReplaceFieldData(baseNode, fieldName, dr[i].ToString(), table.Columns[i].DataType);
        }
        tableNode.InsertBefore(baseNode, templateRowNode);
    }

    private void TransformDataTable(DataTable dt)
    {
        this.TransformWordMLTableRepeat(dt);
        this.TransformWordMLElementRepeat(dt);
        this.TransformNoRepeat(dt);
    }

    private void TransformDataTable_row(DataTable dt)
    {
        this.TransformWordMLTableRepeat(dt);
        this.TransformWordMLElementRepeat(dt);
        this.TransformNoRepeat_row(dt);
    }

    private void TransformNoRepeat(DataTable dt)
    {
        if (dt.Rows.Count > 0)
        {
            DataRow row = dt.Rows[0];
            for (int i = 0; i < row.ItemArray.Length; i++)
            {
                string fieldName = dt.TableName + dt.Columns[i].ColumnName;
                this.ReplaceFieldData(this.xmlTemplateDoc.DocumentElement, fieldName, row[i].ToString(), dt.Columns[i].DataType);
            }
        }
    }

    private void TransformNoRepeat_row(DataTable dt)
    {
        if (dt.Rows.Count > 0)
        {
            for (int i = 0; i < dt.Columns.Count; i++)
            {
                if (LIB.Core.LibTable.FindColumn(dt, "ma") >= 0)
                {
                    for (int j = 0; j < dt.Rows.Count; j++)
                    {
                        string fieldName = dt.TableName + dt.Columns[i].ColumnName + dt.Rows[j]["ma"].ToString().Trim();
                        this.ReplaceFieldData(this.xmlTemplateDoc.DocumentElement, fieldName, dt.Rows[j][i].ToString(), dt.Columns[i].DataType);
                    }
                }
            }
        }
    }

    private void TransformWordMLElementRepeat(DataTable dt)
    {
        string tableName = dt.TableName;
        XmlNodeList list = this.xmlTemplateDoc.SelectNodes("//w:p[contains(descendant::aml:annotation/@w:name, '" + tableName + "WMLRepeat') and (contains(descendant::w:instrText, ' MERGEFIELD \"" + tableName + "') or contains(descendant::w:instrText, ' MERGEFIELD " + tableName + "'))]", this.nsmgr);
        if ((list != null) && (list.Count > 0))
        {
            foreach (XmlNode node in list)
            {
                foreach (DataRow row in dt.Rows)
                {
                    this.TransformDataRow(row, node);
                }
            }
        }
    }

    private void TransformWordMLTableRepeat(DataTable dt)
    {
        string tableName = dt.TableName;
        XmlNodeList list = this.xmlTemplateDoc.SelectNodes("//w:tbl[contains(descendant::aml:annotation/@w:name, '" + tableName + "WMLRepeat') and (contains(descendant::w:instrText, ' MERGEFIELD  \"" + tableName + "') or contains(descendant::w:instrText, ' MERGEFIELD  " + tableName + "'))]", this.nsmgr);
        if ((list != null) && (list.Count > 0))
        {
            foreach (XmlNode node2 in list)
            {
                XmlNode templateRowNode = node2.SelectSingleNode("w:tr[contains(descendant::w:instrText, ' MERGEFIELD  \"" + tableName + "') or contains(descendant::w:instrText, ' MERGEFIELD  " + tableName + "')]", this.nsmgr);
                if (templateRowNode != null)
                {
                    foreach (DataRow row in dt.Rows)
                    {
                        this.TransformDataRow(row, node2, templateRowNode);
                    }
                    node2.RemoveChild(templateRowNode);
                }
            }
        }
    }

    public ArrayList ErrorList
    {
        get
        {
            return this.errorList;
        }
    }

    public bool OperationFailed
    {
        get
        {
            return this.bOperationFailed;
        }
    }

    public XmlDocument WordMLDocument
    {
        get
        {
            return this.xmlTemplateDoc;
        }
    }
}

